package com.example.demo_mysql_mybatisplus.util.responce.results.filler.core;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.example.demo_mysql_mybatisplus.util.responce.results.filler.FillResponceInterface;
import com.example.demo_mysql_mybatisplus.util.responce.results.filler.FillResponces;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

@Aspect
@Component
@Slf4j
public class FillResponcesAop {

    private Map<Class, Handler> handlersMap = new HashMap<>();

    @Resource
    private FillResponceInterface fillResponceInterface;


    @AfterReturning(value = "@annotation( fillResponces )", returning = "resultData")
    public void doAfter(JoinPoint joinPoint, Object resultData, FillResponces fillResponces) throws Exception {
        log.info( "fillResponce - start -------------- "+joinPoint.getSignature().toShortString() );
        if(null!=resultData){
            log.info( "fillResponce - 填充前："+JSONUtil.toJsonStr(resultData) );

            FillResponce[] paramsArr = fillResponces.value();
            if(null!=paramsArr && paramsArr.length>0){
                fillHandlersMap( paramsArr );
                fillEntity( resultData );
                fillTransFieldsVal();
            }
        }
        log.info( "fillResponce - 填充后："+JSONUtil.toJsonStr(resultData) );
        log.info( "fillResponce - 过程数据："+JSONUtil.toJsonStr(handlersMap) );
        log.info( "fillResponce - end -------------- "+joinPoint.getSignature().toShortString() );
    }


    /** 1、填充对象、fromField、transFields 到map */
    private void fillHandlersMap(FillResponce[] paramsArr ) throws NoSuchFieldException {
        for (FillResponce fillResponce : paramsArr) {
            Handler handler = new Handler();
            handler.setTargetClass( fillResponce.target() );
            handler.setByField( fillResponce.by() );
            handler.setUseMethod( fillResponce.useMethod() );
            // fill transFields
            List<String> transFields = new LinkedList<>();
            if( !"".equals(fillResponce.fillFields())){
                for (String fillField : Arrays.asList(fillResponce.fillFields().split(","))) {
                   if(getField(handler.getTargetClass(), fillField)==null){
                       throw new NoSuchFieldException( fillField );
                   }
                    transFields.add(fillField);
                }
            }else if(fillResponce.defaultFields()){
                transFields.add("code");
                transFields.add("name");
            }else if(fillResponce.allFields()){
                for (Field declaredField : handler.getTargetClass().getDeclaredFields()) {
                    if(Constants.BASE_TYPES.contains(declaredField.getType())){
                        transFields.add(declaredField.getName());
                    }
                }
            }
            handler.setFillFields( transFields );
            // check params
            if(handler.checkParams()){
                handlersMap.put( handler.getTargetClass() ,handler);
            }
        }
    }

    /** 2、递归填充实体类、fromField的值到map */
    private void fillEntity(Object responcerObject) throws IllegalAccessException {
        if (null!=responcerObject) {
            if( responcerObject instanceof Collection){
                for (Object responcer : (Collection)responcerObject) {
                    dealEntity( responcer );
                }
            }else{
                dealEntity( responcerObject );
            }
        }
    }
    private void dealEntity(Object responcerObject) throws IllegalAccessException {
        if (null!= responcerObject && !Constants.BASE_TYPES.contains(responcerObject.getClass())){
            Class<?> cla = responcerObject.getClass();
            Handler handler = handlersMap.get(cla) ;
            if(null!=handler){
                // 填充实体类
                handler.getResponceEntitys().add(responcerObject);
                // 填充fromField的值
                Field fromField = getField(cla, handler.getByField());
                if(null!=fromField){
                    fromField.setAccessible(true);
                    Object val = fromField.get(responcerObject) ;
                    if(null!=val){
                        handler.getByFieldValues().add(val) ;
                    }
                }
            }
            for (Field declaredField : cla.getDeclaredFields()) {
                if( !Constants.BASE_TYPES.contains(declaredField.getType()) ){
                    declaredField.setAccessible(true);
                    Object declaredFieldObject = declaredField.get(responcerObject);
                    fillEntity( declaredFieldObject);
                }
            }
        }
    }

    /** 3、校验并填充需要转换字段的值
     * */
    private void fillTransFieldsVal() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Iterator<Map.Entry<Class, Handler>> iter = handlersMap.entrySet().iterator();
        while (iter.hasNext()) {
            Map.Entry<Class, Handler> entry = iter.next();
            Handler handler = entry.getValue();
            // check params
            if(handler.getResponceEntitys().size()==0 || handler.getByFieldValues().size()==0){
                iter.remove();
            }
            // fill val
            Class dataClass = fillResponceInterface.getClass();
            Method method = dataClass.getMethod(handler.getUseMethod(),String.class,List.class);// 限定实现类参数类型
            if( null!=method ){
                Object dataObject = method.invoke(fillResponceInterface,handler.getByField(), handler.getByFieldValues() );
                if(dataObject!=null){
                    if( dataObject instanceof Collection){
                        for (Object data : (Collection)dataObject) {
                            dealTransFieldsVal( data);
                        }
                    }else{
                        dealTransFieldsVal( dataObject);
                    }
                }
            }
        }
    }
    private void dealTransFieldsVal(Object dataObject) throws IllegalAccessException {
        if (null!=dataObject && !Constants.BASE_TYPES.contains(dataObject.getClass())){
            Class<?> cla = dataObject.getClass();
            Handler handler = handlersMap.get(cla) ;
            if(null!=handler){
                Field fromField = getField(cla, handler.getByField());
                if(null!=fromField){
                    fromField.setAccessible(true);
                    for (Object entity : handler.getResponceEntitys()) {
                        Object fromFieldOfData = fromField.get(dataObject);
                        Object fromFieldOfEntity = fromField.get(entity);
                        if(ObjectUtil.equal( fromFieldOfEntity ,fromFieldOfData ) ){
                            for (String transField : handler.getFillFields()) {
                                Field field = getField(cla, transField);
                                if(null!=field){
                                    field.setAccessible(true);
                                    field.set(entity, field.get(dataObject) );
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /** 递归查找字段，应对继承场景 */
    private Field getField(Class<?> clas,String FieldName){
            try {
                return clas.getDeclaredField(FieldName);
            } catch (NoSuchFieldException e2) {
                Class<?> superCla = clas.getSuperclass();
                if( null!=superCla){
                    return getField( superCla, FieldName);
                }
            }
        return null;
    }

}

